import { dayjs } from 'element-plus'
import XLSX from 'xlsx-js-style'
import type { CellObject } from 'xlsx-js-style'
interface DownLoadExcelParams {
  data: any[]
  props: TableXlsxColumnProp[]
  fileName: string
}

interface Style {
  backgroundColor?: string
  ['background-color']?: string
  color?: string
  fontWeight?: string
  ['font-weight']?: string
  fontStyle?: string
  ['font-style']?: string
  textDecoration?: string
  ['text-decoration']?: string
  textAlign?: string
  ['text-align']?: string
  fontSize?: string
  ['font-size']?: string
}
export function useXlsx() {
  const onFileData = (binary: string, xlsxProps: TableXlsxColumnProp[]) => {
    try {
      const workbook = XLSX.read(binary, { type: 'binary', cellDates: true })
      const dataList: unknown[][] = []
      workbook.SheetNames.forEach((sheetName) => {
        const worksheet = workbook.Sheets[sheetName]
        const data = XLSX.utils.sheet_to_json(worksheet)
        if (data.length) {
          dataList.push(onSheetJson(data as any[], xlsxProps))
        }
      })

      return dataList
    } catch (error) {
      console.error(error)
    }
  }

  const onSheetJson = (list: any[], xlsxProps: TableXlsxColumnProp[]) => {
    // 判断表头是否合并
    if (xlsxProps.some((p) => p.children)) {
      const keyMapData = list[0]
      list.forEach((item: any) => {
        for (let key in keyMapData) {
          if (item.hasOwnProperty(key)) {
            item[keyMapData[key]] = item[key]
          }
        }
      })
      list.shift()
    }
    return list.map((item) => onSheetItem(item, xlsxProps))
  }

  const onSheetItem = (item: any, xlsxProps: TableXlsxColumnProp[]) => {
    let data: CommonObject = {}
    const flatProps = onFlat(xlsxProps)
    for (let key in item) {
      const prop = flatProps.find((p) => p.label === key)
      if (!prop) continue
      const value = item[key]
      data[prop.key] = value
    }
    return data
  }
  const onDownLoadExcel = ({ data, props, fileName }: DownLoadExcelParams) => {
    // 处理内容
    const { header, headerMerge, flatProps } = onGetExcelSetting(props)
    let contentArr = onContentArray(data, flatProps)
    let arr = [...header, ...contentArr]
    let sheet = XLSX.utils.aoa_to_sheet(arr, {
      cellDates: true
    })
    sheet['!merges'] = [...headerMerge]
    sheet['!cols'] = flatProps.map((i) => {
      return {
        wch: i.xlsxLength || 28
      }
    })
    onDownloadDialog(onSheet2blob(sheet, fileName), `${fileName}.xlsx`)
  }
  const onGetExcelSetting = (props: TableXlsxColumnProp[]) => {
    const flatProps = onFlat(props)
    const header = onBuildHeader(props)
    const headerMerge = onHeaderMerge(header)
    return {
      header: header.map((i) => i.map((j) => onXlsxCell(j))),
      headerMerge,
      flatProps
    }
  }

  // 扁平头部
  const onFlat = (list: TableXlsxColumnProp[]) => {
    let result: TableXlsxColumnProp[] = []
    list.forEach((e: TableXlsxColumnProp) => {
      if (e.children) {
        result.push(...onFlat(e.children as TableXlsxColumnProp[]))
      } else if (e.hasOwnProperty('key')) {
        result.push(e)
      }
    })
    return result
  }
  const onBuildHeader = (flatProps: TableXlsxColumnProp[]) => {
    let excelHeader: string[][] = []
    onHeaderReplace(flatProps, excelHeader, 0, 0)
    // 多行表头长短不一，短的向长的看齐，不够的补上行合并占位符
    let max = Math.max(...excelHeader.map((a) => a.length))
    excelHeader.filter((e) => e.length < max).forEach((e) => onPushRowSpanPlaceHolder(e, max - e.length))
    return excelHeader
  }

  const onHeaderReplace = (props: TableXlsxColumnProp[], excelHeader: string[][], deep: number, perOffset: number) => {
    let offset = 0
    let cur = excelHeader[deep]
    if (!cur) {
      cur = excelHeader[deep] = []
    }
    onPushRowSpanPlaceHolder(cur, perOffset - cur.length)
    for (let i = 0; i < props.length; i++) {
      let prop = props[i]
      cur.push(prop.label)
      if (prop.hasOwnProperty('children') && Array.isArray(prop.children) && prop.children.length > 0) {
        let childOffset = onHeaderReplace(prop.children, excelHeader, deep + 1, cur.length - 1)
        // 填充列合并占位符
        onPushColSpanPlaceHolder(cur, childOffset - 1)
        offset += childOffset
      } else {
        offset++
      }
    }
    return offset
  }
  const onPushRowSpanPlaceHolder = (arr: string[], count: number) => {
    for (let i = 0; i < count; i++) {
      arr.push('!$ROW_SPAN_PLACEHOLDER')
    }
  }

  const onPushColSpanPlaceHolder = (arr: string[], count: number) => {
    for (let i = 0; i < count; i++) {
      arr.push('!$COL_SPAN_PLACEHOLDER')
    }
  }

  const onHeaderMerge = (header: string[][]) => {
    // 要么横向合并 要么纵向合并
    let deep = header.length
    let merges = []
    for (let y = 0; y < deep; y++) {
      // 先处理横向合并
      let row = header[y]
      let col_span = 0
      for (let x = 0; x < row.length; x++) {
        if (row[x] === '!$COL_SPAN_PLACEHOLDER') {
          row[x] = ''
          if (x + 1 === row.length) {
            merges.push({ s: { r: y, c: x - col_span - 1 }, e: { r: y, c: x } })
          }
          col_span++
        } else if (col_span > 0 && x > col_span) {
          merges.push({ s: { r: y, c: x - col_span - 1 }, e: { r: y, c: x - 1 } })
          col_span = 0
        } else {
          col_span = 0
        }
      }
    }
    let col_length = header[0].length
    for (let x = 0; x < col_length; x++) {
      let row_span = 0
      for (let y = 0; y < deep; y++) {
        if (header[y][x] === '!$ROW_SPAN_PLACEHOLDER') {
          header[y][x] = ''
          if (y + 1 === deep) {
            merges.push({ s: { r: y - row_span - 1, c: x }, e: { r: y, c: x } })
          }
          row_span++
        } else if (row_span > 0 && y > row_span) {
          merges.push({ s: { r: y - row_span - 1, c: x }, e: { r: y - 1, c: x } })
          row_span = 0
        } else {
          row_span = 0
        }
      }
    }
    return merges
  }

  const onContentArray = (data: any[], props: TableXlsxColumnProp[]) => {
    return data.map((item) => onExportItem(item, props))
  }
  const onExportItem = (item: any, props: TableXlsxColumnProp[]) => {
    let temp_arr = []
    for (let prop of props) {
      let value = onPropKey(prop, item[prop.key])
      temp_arr.push(onXlsxCell(value, prop))
    }
    return temp_arr
  }
  const onPropKey = (prop: TableXlsxColumnProp, value: any) => {
    let type = prop.xlsxType
    let data = value
    switch (type) {
      default:
        break
    }
    if (['undefined', 'null', 'NaN', undefined, null].includes(value)) {
      data = ''
    }
    return data
  }
  const onSheet2blob = (sheet: XLSX.WorkSheet, sheetName: string) => {
    sheetName = sheetName || 'sheet1'
    let workbook: XLSX.WorkBook = {
      SheetNames: [sheetName],
      Sheets: {}
    }
    workbook.Sheets[sheetName] = sheet
    let wordOptions: XLSX.WritingOptions = {
      bookType: 'xlsx',
      type: 'binary'
    }
    let workBout = XLSX.write(workbook, wordOptions)
    let blob = new Blob([s2ab(workBout)], {
      type: 'application/octet-stream'
    })
    function s2ab(s: any) {
      let buf = new ArrayBuffer(s.length)
      let view = new Uint8Array(buf)
      for (let i = 0; i !== s.length; ++i) {
        view[i] = s.charCodeAt(i) & 0xff
      }
      return buf
    }
    return blob
  }
  /**
   * @param url 下载地址，可以是字符串或 Blob 对象，必选
   * @param saveName 保存文件名，可选
   */
  const onDownloadDialog = (url: string | Blob, saveName: string = '') => {
    // 将 Blob 对象转换为 URL
    if (url instanceof Blob) {
      url = URL.createObjectURL(url) // 创建blob地址
    }

    // 创建下载链接
    const aLink = document.createElement('a')
    aLink.href = url
    aLink.download = saveName

    // 设置链接样式为不影响样式
    aLink.style.display = 'none' // 隐藏链接
    document.body.appendChild(aLink) // 添加到文档中

    // 触发下载
    const event = new MouseEvent('click', {
      bubbles: true,
      cancelable: true,
      view: window
    })
    aLink.dispatchEvent(event)

    // 移除链接
    document.body.removeChild(aLink)

    // 释放 Blob URL
    if ((url as any) instanceof Blob) {
      URL.revokeObjectURL(url)
    }
  }

  const onXlsxCell = (text: string, prop?: TableXlsxColumnProp) => {
    let style: Style | undefined = undefined
    let type = 's'
    let extraStyle = {}
    if (prop) {
      if (prop.xlsxType === 'date') {
        type = 'd'
        extraStyle = {
          z: 'm/d/yy',
          w: '10/21/24'
        }
      } else if (prop.xlsxType === 'custom') {
        switch (text) {
          case '红字黑底':
            style = {
              color: `rgb(239,68,68)`,
              backgroundColor: '#000000'
            }
            break
          case '绿字红底':
            style = {
              color: `rgb(34,197,94)`,
              backgroundColor: `rgb(239,68,68)`
            }
            break
          case '白字黑底':
            style = {
              color: '#ffffff',
              backgroundColor: '#000000'
            }
            break
          default:
            break
        }
      }
    }
    return {
      v: text,
      t: type,
      s: onXlsxStyleConvert(style),
      ...extraStyle
    } as CellObject
  }

  const onXlsxStyleConvert = (style?: Style) => {
    let xlsxStyle = {
      alignment: {
        horizontal: 'center',
        vertical: 'center'
      },
      font: {
        color: { rgb: '000000' }
      },
      fill: {
        bgColor: { rgb: 'FFFFFF' }
      },
      border: {
        top: { style: 'thin' },
        bottom: { style: 'thin' },
        left: { style: 'thin' },
        right: { style: 'thin' }
      }
    } as any
    if (!style) return xlsxStyle
    if (style.backgroundColor && style.backgroundColor !== 'transparent') {
      xlsxStyle.fill = {
        fgColor: { rgb: normalizeColor(style.backgroundColor) }
      }
    }
    if (style.color) {
      xlsxStyle.font.color = { rgb: normalizeColor(style.color) }
    }
    if (style.fontWeight === 'bold') {
      xlsxStyle.font.bold = true
    }
    if (style.fontStyle === 'italic') {
      xlsxStyle.font.italic = true
    }
    if (style.textDecoration === 'underline') {
      xlsxStyle.font.underline = true
    }
    if (style.textDecoration === 'line-through') {
      xlsxStyle.font.strike = true
    }
    return xlsxStyle
  }

  function normalizeColor(color: string) {
    if (!color) return 'ffffff'
    if (color.startsWith('#')) {
      // 如果是#RRGGBB或#RRGGBBAA，则不做处理
      if (color.length === 7 || color.length === 9) return color.replace('#', '')
      // 如果是#RGB，则转换为#RRGGBB
      if (color.length === 4) {
        return color[1].repeat(2) + color[2].repeat(2) + color[3].repeat(2)
      }
      // 无效格式
      return 'ffffff'
    }
    if (color.startsWith('rgb(')) {
      // 解析rgb值并转换为#RRGGBB
      const match = color.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
      if (match) {
        const r = parseInt(match[1], 10).toString(16).padStart(2, '0')
        const g = parseInt(match[2], 10).toString(16).padStart(2, '0')
        const b = parseInt(match[3], 10).toString(16).padStart(2, '0')
        return r + g + b
      }
      // 无效格式
      return 'ffffff'
    }
    // 无效格式
    return 'ffffff'
  }
  return { onFileData, onDownLoadExcel }
}
